<template>
  <Row :gutter="5" style="padding: 0; background: transparent">
    <Col span="12">
      <Card title="Web Api接口调用" size="small" :bodyStyle="formStyle">
        <Form :selfUpdate="true" :label-col="{ style: { width: '80px' } }">
          <Form.Item label="Host">
            <Select v-model:value="config.host">
              <Select.Option v-for="item of config.hosts" :value="item.url">{{ item.name }}</Select.Option>
            </Select>
          </Form.Item>
          <Form.Item label="Api">
            <Select v-model:value="config.api" @change="changeApi">
              <Select.Option v-for="(item, index) of config.apis" :value="index">{{ item.name }} - {{ item.url }}</Select.Option>
            </Select>
          </Form.Item>
          <Form.Item :class="item.formItemClasses" v-for="(item, index) of request" :label="item.desc" :name="item.name">
            <Tooltip v-if="!item.isNew" :title="item.desc + '为必填项！'" :disabled="!!item.value" placement="topLeft" theme="dark">
              <Row :gutter="5">
                <Col span="9">
                  <Input v-model:value="item.name" readonly />
                </Col>
                <Col span="4">
                  <Input v-model:value="item.type" readonly />
                </Col>
                <template v-if="item.handler">
                  <Col span="11">
                    <template v-if="item.handler == 'getProjects' || item.handler == 'getProcessGroups'">
                      <AutoComplete v-model:value="item.value" :ref="item.handler" allowClear :backfill="true" :filter-option="filterOption" :options="options[item.handler]" option-label-prop="value" @click.once="getHandlerDatas(item)" @change="optionChanged(item)">
                        <template #option="opt">{{ opt.text }}</template>
                        <Input>
                          <template #suffix><DownOutlined /></template>
                        </Input>
                      </AutoComplete>
                    </template>
                    <template v-else>
                      <AutoComplete v-model:value="item.value" :ref="item.handler" allowClear :backfill="true" :filter-option="filterOption" :options="options[item.handler]" option-label-prop="value" @click="getHandlerDatas(item)" @change="optionChanged(item)">
                        <template #option="opt">{{ opt.text }}</template>
                        <Input>
                          <template #suffix><DownOutlined /></template>
                        </Input>
                      </AutoComplete>
                    </template>
                  </Col>
                </template>
                <template v-else>
                  <Col :span="item.ref ? 6 : 11">
                    <Input v-model:value="item.value" @change="validInputs" />
                  </Col>
                  <Col span="5" v-if="item.ref">
                    <Select v-model:value="item.value" allowClear>
                      <Select.Option v-for="option of config.defines[item.ref]" :value="option.value">{{ option.text }}</Select.Option>
                    </Select>
                  </Col>
                </template>
              </Row>
            </Tooltip>
            <Row :gutter="5" v-else>
              <Col span="9">
                <Input v-model:value="item.name" />
              </Col>
              <Col span="4">
                <Select v-model:value="item.type" allowClear>
                  <Select.Option v-for="p of requestTypes" :value="p">{{ p }}</Select.Option>
                </Select>
              </Col>
              <Col span="9">
                <Input v-model:value="item.value" />
              </Col>
              <Col span="1">
                <Button size="small" @click="removeParam(index)" type="primary" danger shape="circle">
                  <DeleteFilled />
                </Button>
              </Col>
            </Row>
          </Form.Item>
          <Form.Item v-if="config.api">
            <Col span="24" style="text-align: right">
              <Button type="primary" size="small" shape="circle" @click="addParams"><PlusCircleFilled /></Button>
              <Button type="default" size="small" shape="circle" @click="showModal = true" style="margin-left: 5px"><CopyFilled /></Button>
            </Col>
          </Form.Item>
          <Form.Item :label-width="0">
            <Col span="24" style="text-align: right">
              <Button @click="search" type="primary" shape="round"> <SearchOutlined /> 查询 </Button>
            </Col>
          </Form.Item>
        </Form>
      </Card>
    </Col>
    <Col span="12" class="code">
      <Card size="small" title="查询结果" :bodyStyle="formStyle">
        <template #extra>
          <Button type="primary" :disabled="jsonData.code != 0" shape="round" @click="onCopyResult"> <CopyFilled /> 复制结果 </Button>
        </template>
        <json-view :json="jsonData" />
      </Card>
    </Col>
  </Row>
  <Modal v-model:visible="showModal" :centered="true" title="复制参数" @ok="onCopy">
    <Input.TextArea v-model:value="conditions" rows="6"></Input.TextArea>
  </Modal>
</template>
<script setup>
  import download from '@/libs/download';
  import jsonView from '@/components/JsonView.vue';

  import { useStore } from 'vuex';
  import { ref, reactive, h, inject, computed, onMounted } from 'vue';
  import { SearchOutlined, CopyFilled, PlusCircleFilled, DeleteFilled, DownOutlined } from '@ant-design/icons-vue';
  import { Card, Modal, Row, Col, Tooltip, Form, Input, AutoComplete, Select, Button } from 'ant-design-vue';

  const $store = useStore();
  const $http = inject('$http');
  const $modal = inject('$modal');
  const $eventBus = inject('$eventBus');
  const $message = inject('$message');
  const $copyText = inject('$copyText');

  const request = ref([]);
  const conditions = ref('');
  const showModal = ref(false);
  const autoHeight = ref(320);

  const config = reactive({ hosts: [], apis: [], api: '', defines: [], host: '' });
  const options = reactive({ getProjects: [], getDepartments: [], getProcesses: [], getProcessGroups: [] });

  const jsonData = reactive({});
  let ruleValidate = reactive({});

  const formStyle = computed(() => {
    let height = autoHeight.value ? autoHeight.value + 15 + 'px' : 'auto';

    return {
      'min-height': height,
      'max-height': height,
      'overflow-y': 'auto',
      'overflow-x': 'hidden'
    };
  });

  const apiDefine = computed(() => config.apis[config.api]);
  const requestTypes = computed(() => $store.state.requestTypes);

  function changeApi() {
    request.value = (config.apis[config.api] || { params: [] }).params;
    ruleValidate = {};

    if (request.value.length > 0) {
      request.value.forEach(el => {
        if (el.required) {
          ruleValidate[el.name] = [
            {
              required: true,
              message: `${el.desc}不能为空！`,
              trigger: ['blur', 'change']
            }
          ];
        }
      });

      validInputs();
    }
  }

  function getConfigs() {
    $http.get('/api/iworkflow/webapi/configs/').then(res => {
      config.hosts = res.hosts;
      config.apis = res.apis;
      config.defines = res.defines;

      config.host = res.hosts[0].url;
    });
  }

  function addParams() {
    if (!apiDefine) {
      $message.error('请先选择api！');

      return;
    }

    let index = request.value.filter(r => r.isNew).length;

    request.value.push({
      desc: `参数${index + 1}`,
      name: '',
      type: apiDefine.method == 'post' ? 'body' : 'query',
      value: '',
      isNew: true
    });
  }

  function removeParam(index) {
    request.value.splice(index, 1);
  }

  function validInputs() {
    request.value.forEach(item => {
      item.formItemClasses = [];
      item.validError = false;

      if (item.required) {
        item.formItemClasses.push('ant-form-item-required');

        if (!item.value) {
          item.formItemClasses.push('ant-form-item-has-error');

          item.validError = true;
        }
      }
    });
  }

  function search() {
    if (!config.host || config.api == undefined) {
      $message.warning('请选择Host和WebApi！');

      return;
    }

    validInputs();

    let datas = request.value.filter(r => r.name);
    let valid = datas.filter(d => d.validError).length == 0;

    if (valid) {
      let requestData = { host: config.host, api: config.apis[config.api].url, data: datas };

      if (datas.find(d => (d.name || '').toLowerCase() == 'isexport' && d.type == 'query' && d.value == 'true')) {
        download.download(`/api/iworkflow/webapi/invoke`, requestData);

        return;
      }

      $http.post(`/api/iworkflow/webapi/invoke`, requestData).then(res => {
        if (res.code == 0) {
          let keys = Object.keys(res);

          keys.forEach(element => {
            jsonData[element] = res[element];
          });
        } else {
          jsonData.code = res.code;
          jsonData.success = false;
          jsonData.message = res.message;
        }
      });
    } else {
      $message.error('请求参数未通过验证，请确认输入必填项！');
    }
  }

  function filterOption(input, option) {
    let casedInput = input.toLowerCase();

    return (option.text || '').toLowerCase().indexOf(casedInput) != -1;
  }

  function onCopy() {
    let params = conditions.value.split('?');
    let items = (params.length > 1 ? params[1] : params[0]).split('&');

    items.forEach(item => {
      if (item) {
        let keyValue = item.split('=');
        let exsits = request.value.find(d => d.name.toLowerCase() == keyValue[0].toLowerCase());

        if (exsits) {
          exsits.value = decodeURI(keyValue[1]);
        } else {
          request.value.push({
            name: keyValue[0],
            type: 'query',
            value: decodeURI(keyValue[1]),
            desc: keyValue[0],
            isNew: true
          });
        }
      }
    });

    conditions.value = '';
    showModal.value = false;
  }

  function onCopyResult() {
    $copyText(JSON.stringify(jsonData, null, 2)).then(() => {
      $message.success('结果已复制！');
    });
  }

  function optionChanged(item) {
    if (!item || !item.value) {
      return;
    }

    if (item.handler == 'getProjects') {
      (request.value.find(c => c.name == 'ExProjectId') || { value: '' }).value = item.value;

      (request.value.find(c => c.name == 'DepartmentID') || { value: '' }).value = '';
      (request.value.find(c => c.name == 'ExDepartmentId') || { value: '' }).value = '';
    }

    if (item.handler == 'getDepartments') {
      (request.value.find(c => c.name == 'ExDepartmentId') || { value: '' }).value = item.value;
    }

    if (item.handler == 'getProcessGroups') {
      (request.value.find(c => c.name == 'ProcessID') || { value: '' }).value = '';
    }

    validInputs();
  }

  function getHandlerDatas(item) {
    switch (item.handler) {
      case 'getProjects':
        getProjects(item);

        break;

      case 'getDepartments':
        getDepartments(item);

        break;

      case 'getProcessGroups':
        getProcessGroups(item);

        break;

      case 'getProcesses':
        getProcesses(item);

        break;
    }
  }

  function getProjects(item) {
    let requestData = { host: config.host, api: '/api/Project/GetAllProjectsForLeo', data: [] };

    $http.post(`/api/iworkflow/webapi/invoke`, requestData).then(res => {
      if (res.code == 0) {
        let result = res.data.map(d => {
          return { text: `${d.ID}(${d.ProjectSN}) - ${d.ProjectName}`, value: d.ID + '' };
        });

        options.getProjects = result;
        options.getDepartments = [];
        options.getProcessGroups = [];
        options.getProcesses = [];
      }
    });
  }

  function getDepartments(item) {
    let projectId = request.value.find(r => r.name == 'ProjectID').value;

    if (!projectId) {
      $message.warning('必须选择项目！');

      return;
    }

    let requestData = {
      host: config.host,
      api: '/api/Department/GetDepartmentIdName',
      data: [{ name: 'projectID', type: 'query', value: projectId }]
    };

    $http.post(`/api/iworkflow/webapi/invoke`, requestData).then(res => {
      if (res.code == 0) {
        let result = res.data.map(d => {
          return {
            text: `${d.id} - ${d.DepartmentName}`,
            value: d.id + ''
          };
        });

        options.getDepartments = result;
        options.getProcessGroups = [];
        options.getProcesses = [];
      }
    });
  }

  function getProcessGroups(item) {
    // let projectId = this.request.find(r => r.name == 'ProjectID').value;
    // let departmentId = this.request.find(r => r.name == 'DepartmentID').value;
    // let userId = this.request.find(r => r.name == 'applyUserID').value;

    let requestData = {
      host: config.host,
      api: '/api/ProcessGroup/GetProcessGroupList',
      data: [
        { name: 'IsDisabled', type: 'query', value: false },
        { name: 'PageSize', type: 'query', value: 20000 }
      ]
    };

    $http.post(`/api/iworkflow/webapi/invoke`, requestData).then(res => {
      if (res.code == 0) {
        let result = res.data.dataList.map(d => {
          return {
            text: d.GroupNameFormatted,
            value: d.ID + '',
            GroupCode: d.GroupCode
          };
        });

        options.getProcessGroups = result;
        options.getProcesses = [];
      }
    });
  }

  function getProcesses(item) {
    let groupId = request.value.find(r => r.name == 'ProcessGroupID').value;

    if (!groupId) {
      $message.warning('必须选择流程组！');

      return;
    }

    let group = options.getProcessGroups.find(c => c.value == groupId);

    let requestData = {
      host: config.host,
      api: '/api/Process/GetProcessListByGroupCode',
      data: [{ name: 'groupCode', type: 'query', value: group.GroupCode }]
    };

    $http.post(`/api/iworkflow/webapi/invoke`, requestData).then(res => {
      if (res.code == 0) {
        let result = res.data.map(d => {
          return {
            text: `${d.ID} - ${d.WorkflowCNName}`,
            value: d.ID + ''
          };
        });

        options.getProcesses = result;
      }
    });
  }

  onMounted(() => {
    getConfigs();
    autoHeight.value = $store.state.area.content.height - 95;

    $eventBus.on('windowResizeChanged', client => {
      autoHeight.value = client.height - 95;
    });
  });
</script>
<style lang="less" scoped>
  .config-split {
    margin-top: 15px;
    margin-bottom: 8px;
    padding-bottom: 5px;
    padding-left: 20px;
    font-weight: bold;
    font-style: italic;
    border-bottom: 1px dashed #ccc;
  }

  .code {
    margin-top: 0;
    margin-bottom: 0;
    border-radius: 5px;
    overflow: hidden;

    .ant-card-extra {
      padding: 0 !important;
    }
  }

  .ant-tooltip {
    width: 100%;
  }
</style>
